package rdb

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"sync"
)

type BitMap interface {
	TopicKey(id any) string
	RedisClient() *redis.Client
	SetIndex(id any, index uint, status bool) error
	GetIndex(id any, index uint) (bool, error)
	GetAllToBinary(id any) (string, error)
	GetAll(id any) ([]byte, error)
	ClearAll(id any) error
}

type _bitMap struct {
	Topic string        //主题
	Redis *redis.Client //Redis客户端
	RWL   sync.RWMutex  //读写锁
}

func NewBitMap(client *redis.Client, topic string) BitMap {
	return &_bitMap{
		Topic: topic,
		Redis: client,
		RWL:   sync.RWMutex{},
	}
}

// TopicKey 返回默认生成的主题key
func (bm *_bitMap) TopicKey(id any) string {
	return fmt.Sprint("BitMap_", bm.Topic, "_", id)
}

// RedisClient 返回绑定的Redis客户端
func (bm *_bitMap) RedisClient() *redis.Client {
	return bm.Redis
}

// SetIndex 设置指定位的状态，1 true，0 false
func (bm *_bitMap) SetIndex(id any, index uint, status bool) error {
	bm.RWL.Lock()
	value := 0
	if status {
		value = 1
	} else {
		value = 0
	}
	err := bm.Redis.SetBit(context.Background(), bm.TopicKey(id), int64(index), value).Err()
	bm.RWL.Unlock()
	return err
}

// GetIndex 获取指定位的状态，1 true，0 false
func (bm *_bitMap) GetIndex(id any, index uint) (bool, error) {
	bm.RWL.RLock()
	result, err := bm.Redis.GetBit(context.Background(), bm.TopicKey(id), int64(index)).Result()
	bm.RWL.RUnlock()
	value := false
	if result == 0 {
		value = false
	} else {
		value = true
	}
	return value, err
}

// GetAllToBinary 返回所有的二进制，返回内容为二进制01的组合
func (bm *_bitMap) GetAllToBinary(id any) (string, error) {
	bm.RWL.RLock()
	result, err := bm.Redis.Get(context.Background(), bm.TopicKey(id)).Bytes()
	bm.RWL.RUnlock()
	if err != nil {
		return "", err
	}
	return byteToBinaryString(result), nil
}

// byteToBinaryString 将byte数组，转换为二进制字符串
func byteToBinaryString(all []byte) string {
	var result string
	for _, d := range all {
		result += fmt.Sprintf("%08b", d)
	}
	return result
}

// GetAll 返回所有的内容，并转成 []byte
func (bm *_bitMap) GetAll(id any) ([]byte, error) {
	bm.RWL.RLock()
	result, err := bm.Redis.Get(context.Background(), bm.TopicKey(id)).Bytes()
	bm.RWL.RUnlock()
	return result, err
}

// Bit1CountAll 返回存储的内容，比特位为1的数量
func (bm *_bitMap) Bit1CountAll(id any) (int64, error) {
	return bm.Bit1Count(id, 0, -1)
}

// Bit1Count 返回存储的内容，指定范围比特位为1的数量；
// start 开始位置
// end 结束位置，比如 -1 表示最后一个字节， -2 表示倒数第二个字节，以此类推。
func (bm *_bitMap) Bit1Count(id any, start int64, end int64) (int64, error) {
	bm.RWL.RLock()
	result, err := bm.Redis.BitCount(context.Background(), bm.TopicKey(id), &redis.BitCount{
		Start: start,
		End:   end,
	}).Result()
	bm.RWL.RUnlock()
	return result, err
}

// ClearAll 清空所有的记录（直接删除key）
func (bm *_bitMap) ClearAll(id any) error {
	bm.RWL.Lock()
	err := bm.Redis.Del(context.Background(), bm.TopicKey(id)).Err()
	bm.RWL.Unlock()
	return err
}
